import '../assets/style/common.less'
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import * as CANNON from 'cannon-es'

const scene = new THREE.Scene();
scene.background = new THREE.Color('#163038')
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(1, 5, 10);
camera.lookAt(0, 0, 0);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 轨道控制器
const controls = new OrbitControls( camera, renderer.domElement );
// 坐标轴
const axesHelper = new THREE.AxesHelper( 5 );
scene.add( axesHelper );

// 几何
const plane = new THREE.PlaneGeometry(40, 40)
// 材质
const baseMaterial = new THREE.MeshStandardMaterial({
  color: new THREE.Color('#66ccff')
})

// 物体
const mesh = new THREE.Mesh(plane, baseMaterial)
mesh.position.set(0,0,0)
mesh.rotateX(-Math.PI / 2)
scene.add(mesh)

function createMesh() {
  // 几何
  const sphere = new THREE.SphereGeometry(1, 30, 30)
  // 材质
  const sphereMaterial = new THREE.MeshStandardMaterial({
    color: new THREE.Color('#aacc00'),
  })
  // 打开线框模式
  sphereMaterial.wireframe = true
  // 物体
  const shpereMesh = new THREE.Mesh(sphere, sphereMaterial)
  shpereMesh.position.set(0,10,0)
  scene.add(shpereMesh)
  return shpereMesh
}

// 物理世界
const world = new CANNON.World({
  gravity: new CANNON.Vec3(0, -9.8, 0)
})

// 物理球
// 给小球添加碰撞事件
const sound = new Audio('../assets/sound/钢管落地.mp3')
sound.muted = true

function createBody () {
  const x = Math.random() * 5
  const z = Math.random() * 5
  const shpereWorld = new CANNON.Sphere(1)
  const shpereBody = new CANNON.Body({
    shape: shpereWorld, // 形状
    mass: 2, // 质量
    material: new CANNON.Material({
      restitution: 0.8, // 默认弹性
      friction: 3.0 // 默认摩擦力
    }),
    position: new CANNON.Vec3(0, 10, 0)
  })
  shpereBody.addEventListener('collide', (e) => {
    const level = e.contact.getImpactVelocityAlongNormal()
    if(level > 5) {
      // 设置播放时间,为0则是从头开始播放
      sound.currentTime = 0
      // 设置声音根据碰撞强度
      sound.volume = Math.floor(level) / 20
      setTimeout(() => {
        sound.play()
      },0)
    }
  })
  world.addBody(shpereBody)
  // 施加力
  shpereBody.applyLocalForce(
    new CANNON.Vec3(x * 100, 0, z * 100), // 施加的力的向量
    new CANNON.Vec3(0.5, 0.5, 0.5),// 施加力在物体上的位置
  )
  return shpereBody
}

// 物理地板
const planeWorld = new CANNON.Plane()
const planeBody = new CANNON.Body({
  mass: 0,
  material: new CANNON.Material({
    restitution: 0.6, // 默认弹性
    friction: 3.0 // 默认摩擦力
  }),
  position: new CANNON.Vec3(0, 0, 0),
  shape: planeWorld,
})
planeBody.quaternion.setFromAxisAngle(new CANNON.Vec3(1, 0, 0), -Math.PI / 2)
world.addBody(planeBody)


// 环境光
const ambientLight = new THREE.AmbientLight('#ffffff')
scene.add(ambientLight)

const clock = new THREE.Clock()

const entities = []
function pushShpere() {
  entities.push({
    mesh: createMesh(),
    body: createBody()
  })
}
window.addEventListener('click', pushShpere)

function animate() {
  requestAnimationFrame(animate);
  const lastTime = clock.getDelta()
  controls.update()
  // 更新物理世界.1/60就是60帧,lastTime用于确定每帧更新时间,不传也行,但是可能会导致帧数不稳定
  world.step(1/60, lastTime)
  // shpereMesh.position.copy(shpereBody.position)
  entities.forEach(entity => {
    // 更新渲染世界物体位置
    entity.mesh.position.copy(entity.body.position)
    // 更新渲染世界物体旋转矩阵
    entity.mesh.quaternion.copy(entity.body.quaternion)
  })

  renderer.render(scene, camera);
}
animate()

window.addEventListener('resize', () => {
  const width = window.innerWidth;
  const height = window.innerHeight;
  renderer.setSize(width, height);
  camera.aspect = width / height;
  camera.updateProjectionMatrix();
});